import json
# from auto_dj_test.conf.CustomRequestHandler import MyLogger

from django.contrib.auth import get_user_model
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import BasePermission
from rest_framework import exceptions, HTTP_HEADER_ENCODING
from django.utils.translation import gettext_lazy as _
from rest_framework_simplejwt.exceptions import AuthenticationFailed

from auto_dj_test import redis_connect
from auto_dj_test.conf.MyLogger import MyLogger

User = get_user_model()


class RedisTokenAuthentication(TokenAuthentication, MyLogger):

    def __init__(self):
        TokenAuthentication.__init__(self)
        MyLogger.__init__(self, f"{__name__}:{self.__class__.__name__}")

    def authenticate(self, request):
        token = request.META.get('HTTP_AUTHORIZATION', '')
        if isinstance(token, str):
            token = token.encode(HTTP_HEADER_ENCODING)
        token = token.split()
        # self.logger.info("authenticate进行校验token")
        if not token:
            msg = _(f'无token')
            raise exceptions.AuthenticationFailed(msg)
        if not token and token[0].lower() == self.keyword.lower().encode():
            msg = _(f'token无效{token[0].lower()}')
            raise exceptions.AuthenticationFailed(msg)
        if len(token) == 1:
            msg = _('Invalid token header. No credentials provided.')
            raise exceptions.AuthenticationFailed(msg)
        elif len(token) > 2:
            msg = _('Invalid token header. Token string should not contain spaces.')
            raise exceptions.AuthenticationFailed(msg)

        try:
            token = token[1].decode()
        except UnicodeError:
            msg = _('Invalid token header. Token string should not contain invalid characters.')
            raise exceptions.AuthenticationFailed(msg)
        return self.authenticate_credentials(token)

    # 请求头 Authorization: Token <your_token_here>
    # 没有重写父类的 authenticate ，如果不带请求头会先被拦截，走不到authenticate_credentials这里
    # 重写父类的 authenticate_credentials  方法，用于验证令牌有效性的具体方法
    def authenticate_credentials(self, key) -> object:
        """
        该方法 检测token是否在redis里面，然后将用户信息返回（后面可以用request.user获取用户的信息），然后到permission进行校验权限
        :param key:
        :return:
        """

        # 从redis通过key（token）获取已经登录的用户信息
        # self.logger.info(f"进行校验token{key}")

        user_data = redis_connect.get(key)
        if user_data:
            # 将 JSON 字符串转换为字典
            user_dict = json.loads(user_data)
            # self.logger.info(f"redis获取的用户信息{user_dict['username']}")
            return user_dict, key

        raise exceptions.AuthenticationFailed(_(f'无效的token--{key}'))


class RedisPermission(BasePermission, MyLogger):
    message = {"status": 403, "msg": "请向管理员申请权限"}

    def __init__(self):
        BasePermission.__init__(self)
        MyLogger.__init__(self, f"{__name__}:{self.__class__.__name__}")

    def has_permission(self, request, view) -> bool:
        # 获取请求的HTTP方法和路径
        http_method = request.method
        api_path = request.path
        self.logger.info(f"进行权限校验，{http_method},{api_path}")
        permissions = request.user['permissions']
        # self.logger.info(f"该用户的权限如下，{permissions}")
        return self.checkPermission(http_method, api_path, permissions)

    def checkPermission(self, http_method, api_path, permissions):
        parts = api_path.strip("/").split("/")
        # 使用循环获取项目名称
        name = None
        i = len(parts)
        for part in parts[::1]:
            if not part.isdigit():
                name = part
        # self.logger.info(f"获取的路径项目：{name}")
        if http_method == "GET":
            name = f"view_{name}"
        elif http_method == "POST":
            name = f"add_{name}"
        elif http_method == "DELETE":
            name = f"delete_{name}"
        elif http_method == "PATCH":
            name = f"change_{name}"
        if name in permissions:
            self.logger.info(f"{name}权限验证通过")
            return True
        else:
            self.logger.warn(f"{name}权限验证不通过")
            # self.logger.warn(f"{name}权限验证不通过,该用户权限如下{permissions}")
            return False
